Another try at using Neovim more seriously
Advent of Code is always a good opportunity to pick up a new programming language, or do anything else to alter your workflow for a bit.
Privately, I've mostly been writing Rust recently (2-3 years?), and for that I've been using Visual Studio Code, because it's insanely painless to get started with, and I honestly don't really value deep customization that much usually. I just want it to work, and I'll get used to the warts.
Well, in a bid to change that fact about myself, I want to do all of the next AoC in Neovim[1]. Specifically nvim-qt
, because Windows (for now). Though I also have a laptop that runs a *nix, and I will sync my config over there eventually and see how it goes.
To be quite honest, I've used both vim and nvim in the past, but even then, mostly just running on defaults and maybe three plugins. Before I started using Obsidian, I tried vimwiki for largely the exact same thing. I also administer a remote machine, doing all my editing through vim there.
Overall, I don't think I'm very good at controlling vim, but I'm not really intimidated by it either. I just never majorly customized it. I explicitly don't want to use a distribution like LazyVim or AstroNvim, because I think I'll be more effective in overcoming my config-complacency by adding things proactively, rather than than removing them from a complete package.
So, that's my plan for AoC2023: Solve the problems, note down things that annoyed me (both config/tooling-wise and my-ability-to-vim-wise), then consciously fix them. Also, write a post about doing that every day.
I do want to have a functioning editor for when I start, so I'm gonna set up at least some sane basics (like line numbers) and an LSP. That's this post.
...or it would be, but kickstart.nvim exists. It's more or less a single-file config "template" that gives you something to work with beyond an empty init.lua
.
So instead of starting from nothing, I'll spend this time making it my own a little bit.
First: I don't like very big config files
As of time of writing, kickstart.nvim
s init.lua
is 600 lines; though a lot of that is helpful explanatory comments and section headers. So let's go through it, stripping comments we don't need, and breaking sections up into separate files. Big scary blocks I'll just shuffle away without worrying about them just yet.
After I complete my first side quest: Pasting things from clipboard into Nvim.
Splitting stuff up.
Now that I've pasted in my very own copy of kickstart.nvim
, let's get started. First order of business would honestly be taking all the sections (separated by nice comment section headers), and splitting them out into separate files.
Scanning through it, roughly there's six sections or so:
lazy
installation and plugin setup- basic settings (like tab size, line numbers, etc)
- keymaps
- configuring
telescope
(whatever that is) - configuring
treesitter
(I know that's like a parser thing?) - configuring LSPs
I think require
is how you load extra files, so I quickly :help require
:
:help require
Modules are searched for under the directories specified in 'runtimepath, in the order they appear. (...)
:help runtimepath
lists a dozen or so sub-folders it tries to load from, the most appropriate one seems to be lua/
. Soooo, one :!mkdir lua
and :e lua/settings.lua
later, I can clumsily delete the basic config lines from my init.lua
and put them in lua/settings.lua
instead; and replace the entire thing with a simple require('settings')
. I'll be honest, I used visual mode for this one... but one day I'll probably be better at just hitting a magic keystroke sequence to copy it all.
Anyway, do that five more times, and I end up with this (after a short detour learning about modelines):
-- Install `lazy` package manager, if missing.
local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim'
if not vim.loop.fs_stat(lazypath) then
vim.fn.system {
'git',
'clone',
'--filter=blob:none',
'https://github.com/folke/lazy.nvim.git',
'--branch=stable', -- latest stable release
lazypath,
}
end
vim.opt.rtp:prepend(lazypath)
-- Set leader key as early as possible.
vim.g.mapleader = ' '
vim.g.maplocalleader = ' '
-- Load packages.
require('lazy').setup('plugins')
-- Load my configurations.
require('settings')
require('keymaps')
require('telescope-config')
require('treesitter-config')
require('lsp-config')
-- A `modeline`. When placed within 5 lines of the end or start of the document,
-- it's active and applies the settings listed after the colon, only for this buffer.
-- Frankly, I cannot imagine ever using this feature.
-- vim: ts=2 sts=2 sw=2 et
Factoring out the humongous plugin listing that it comes with by default took reading the README for lazy.nvim—it mentions that the argument to .setup()
can be either a Lua table (as was the case in the original kickstart.nvim
), or a string referring to the module to load instead. Then inside that module (lua/plugins.lua
in my case), you just return
the table that was inlined instead:
return {
'tpope/vim-fugitive',
'tpope/vim-rhubarb',
...
}
Funnily enough, reading lazy.nvim
s README also showed me it was the source of snippet for bootstrapping/installing lazy
present in kickstart.nvim
. Going back and reading first sources is really paying off for me getting a general overview already.
Now it's time to finally launch the thing with a config!
And immediately, Windows happens lol.
A bunch of plugins start installing themselves, I think Mason
pops up by itself? And after a couple seconds, I get an error message. treesitter
can't find a C compiler, which it needs. I end up installing msys2, then gcc
through pacman
. Aaaand adding that to $PATH.
Restarting.
Now treesitter correctly installs itself. I think. It installs a bunch of stuff like grammars for C++ or JavaScript, which I don't really want or need for now. I'm sure it says to download them in the config somewhere. I'll get around to it.
Aaaand it's there!
That definitely looks like a code editor.
And then some more issues
Though, immediately, I get some annoying message asking me stuff I don't understand:
I say 3, aaaand
Alright. That's an LSP thing, so off to lua/lsp-config.lua
I go.
local servers = {
-- clangd = {},
-- gopls = {},
-- pyright = {},
-- rust_analyzer = {},
-- tsserver = {},
-- html = { filetypes = { 'html', 'twig', 'hbs'} },
lua_ls = {
Lua = {
workspace = { checkThirdParty = false },
telemetry = { enable = false },
},
},
}
I should read more about how exactly this whole configuration works, but thankfully kickstart.nvim
already had the whole Lua.workspace.checkThirdParty
thing set up, just... with the wrong value, I guess?? Maybe it changed recently, and I just had bad luck or something. Changing that false
to "Disable"
did fix my issue. And while I'm here, I uncommented rust_analyzer
, too, since I wanna be writing Rust.
And that's the minimum viable setup, I guess
Yeah, that's pretty close to all I need, actually. One thing that's Rust-specific, is that it seems to be using cargo check
instead of cargo clippy
to produce diagnostics. That's something I'll have to look into. And I noticed it doesn't autoformat, though the comments in kickstart.nvim
mentioned something about that.
But for now, I'm satisfied. I started a repo with my config, maybe I'll push it to my github at some point—and that's where I leave it until December (or until I do old Advent of Codes because I can't wait).
- go through all plugins included in
kickstart.nvim
; learn about them, or prune them - enable format-on-save for code files
- use
cargo clippy
to produce diagnostics - review motions so I don't hold
j
/k
to navigate through files
Literally the first word you see on their page is "hyperextensible", lmao. ↩︎